/*
 * tick.c
 *
 * realize system tick using Timer0, the period is about 10ms.
 *
 * Copyright (C) 2022 Microwell, Inc.
 * Subject to the GNU Public License, version 2.
 *
 * Author: guoming<guoming@microwell.net>
 */

#ifndef _TIMER_H_
#define _TIMER_H_

#include "config.h"
#include "types.h"

/*=============================================================================
 *                               Tick config
 *===========================================================================*/
#define CONFIG_TICK_TIMER_ID_SYS_EN                (RESET)
#define CONFIG_TICK_TIMER_ID_0_EN                  (RESET)
#define CONFIG_TICK_TIMER_ID_1_EN                  (RESET)
#define CONFIG_TICK_TIMER_ID_2_EN                  (RESET)

#define CONFIG_TICK_TIMER_ID_SYS_INTERRPUT_EN      (RESET)
#define CONFIG_TICK_TIMER_ID_0_INTERRPUT_EN        (RESET)
#define CONFIG_TICK_TIMER_ID_1_INTERRPUT_EN        (RESET)
#define CONFIG_TICK_TIMER_ID_2_INTERRPUT_EN        (RESET)
/**
 * @brief default 8 auto mode timer for pwm
 * TIMER0_MAX_VAL                       (256)
 * CONFIG_TIMER0_TCLKDIV                (CLK_DIV_2)
 * system clock is 12Mhz, then frequency is in the 23,622-3,000,000 range
 */
#define CONFIG_TIMER0_MODE                         (TIMER_8_AUTO_MODE)
#define CONFIG_TIMER0_FREQ                         (200000)
/* 1,2,3,4,6,8,16,32 */
#define CONFIG_TIMER0_TCLKDIV                      (CLK_DIV_2)
/**
 * @brief default 8bit auto mode timer for pwm
 * TIMER1_MAX_VAL                       (256)
 * CONFIG_TIMER1_TCLKDIV                (CLK_DIV_2)
 * system clock is 12Mhz, then frequency is in the 23,622-3,000,000 range
 */
#define CONFIG_TIMER1_MODE                         (TIMER_8_AUTO_MODE)
#define CONFIG_TIMER1_FREQ                         (200000)
/* 1,2,3,4,6,8,16,32 */
#define CONFIG_TIMER1_TCLKDIV                      (CLK_DIV_2)

/**
 * @brief default 13 auto mode timer
 * TIMER2_MAX_VAL                       (8192)
 * CONFIG_TIMER2_TCLKDIV                (CLK_DIV_1)
 * system clock is 12Mhz, then frequency is in the 732-6,000,000 range
 * 
 */
#define CONFIG_TIMER2_FREQ                         (20000)
/* 1,2,3,4,6,8,16,32 */
#define CONFIG_TIMER2_TCLKDIV                      (CLK_DIV_1)

/*=============================================================================
 *                               Tick config end
 *===========================================================================*/
/* default using timer0 for tick; using systick for tick(except ss880x) */
#if (CONFIG_IC_TYPE == CHIP_SS880X)
    #define TICK_TIMER_ID_0_EN                     (SET)
    #define TICK_TIMER_ID_0_INTERRPUT_EN           (SET)
    #define TICK_ENABLE()                          TIMER_0_INTERRUPT_ENABLE()
    #define TICK_DISABLE()                         TIMER_0_INTERRUPT_DISABLE()
#elif (CONFIG_IC_TYPE > CHIP_SS880X)
    #define TICK_TIMER_ID_SYS_EN                   (SET)
    #define TICK_TIMER_ID_SYS_INTERRPUT_EN         (SET)
    #define TICK_ENABLE()                          STICK_INTERRUPT_ENABLE() 
    #define TICK_DISABLE()                         STICK_INTERRUPT_DISABLE()
#else
    #error ("please using systick")
#endif

#if(CC_CHANNEL_MODE || CONFIG_TICK_TIMER_ID_2_EN)
    #define TICK_TIMER_ID_2_EN                     (SET)
#endif

#if ((CONFIG_IC_TYPE > CHIP_SS880X) && (GPIO_P00_PWM_MODE == PWM0))
    #define TICK_TIMER_ID_0_EN                    (SET)
#endif

#if ((GPIO_P01_PWM_MODE | GPIO_P13_PWM_MODE | GPIO_P16_PWM_MODE) || CONFIG_TICK_TIMER_ID_1_EN)
    #define TICK_TIMER_ID_1_EN                    (SET)
#endif

#if ((CONFIG_IC_TYPE == CHIP_SS880X) && (GPIO_P01_PWM_MODE | GPIO_P13_PWM_MODE | GPIO_P16_PWM_MODE) && (GPIO_P00_PWM_MODE == PWM0))
    #error ("please using CC")
#endif

#ifndef TICK_TIMER_ID_SYS_EN
#define TICK_TIMER_ID_SYS_EN                      (CONFIG_TICK_TIMER_ID_SYS_EN)
#endif
#ifndef TICK_TIMER_ID_0_EN
#define TICK_TIMER_ID_0_EN                        (CONFIG_TICK_TIMER_ID_0_EN)
#endif
#ifndef TICK_TIMER_ID_1_EN
#define TICK_TIMER_ID_1_EN                        (CONFIG_TICK_TIMER_ID_1_EN)
#endif
#ifndef TICK_TIMER_ID_2_EN
#define TICK_TIMER_ID_2_EN                        (CONFIG_TICK_TIMER_ID_2_EN)
#endif

#ifndef TICK_TIMER_ID_SYS_INTERRPUT_EN
#define TICK_TIMER_ID_SYS_INTERRPUT_EN            (CONFIG_TICK_TIMER_ID_SYS_INTERRPUT_EN)
#endif
#ifndef TICK_TIMER_ID_0_INTERRPUT_EN
#define TICK_TIMER_ID_0_INTERRPUT_EN             (CONFIG_TICK_TIMER_ID_0_INTERRPUT_EN)
#endif
#ifndef TICK_TIMER_ID_1_INTERRPUT_EN
#define TICK_TIMER_ID_1_INTERRPUT_EN             (CONFIG_TICK_TIMER_ID_1_INTERRPUT_EN)
#endif
#ifndef TICK_TIMER_ID_2_INTERRPUT_EN
#define TICK_TIMER_ID_2_INTERRPUT_EN             (CONFIG_TICK_TIMER_ID_2_INTERRPUT_EN)
#endif

#if (CONFIG_TIMER0_TCLKDIV == CLK_DIV_1)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_1)
#elif (CONFIG_TIMER0_TCLKDIV == CLK_DIV_2)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_2)
#elif (CONFIG_TIMER0_TCLKDIV == CLK_DIV_3)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_3)
#elif (CONFIG_TIMER0_TCLKDIV == CLK_DIV_4)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_4)
#elif (CONFIG_TIMER0_TCLKDIV == CLK_DIV_6)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_6)
#elif (CONFIG_TIMER0_TCLKDIV == CLK_DIV_8)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_8)
#elif (CONFIG_TIMER0_TCLKDIV == CLK_DIV_16)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_16)
#elif (CONFIG_TIMER0_TCLKDIV == CLK_DIV_32)
    #define TIMER0_TCLKDIV                       (TCLK_DIV_32)
#endif

#if (CONFIG_TIMER1_TCLKDIV == CLK_DIV_1)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_1)
#elif (CONFIG_TIMER1_TCLKDIV == CLK_DIV_2)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_2)
#elif (CONFIG_TIMER1_TCLKDIV == CLK_DIV_3)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_3)
#elif (CONFIG_TIMER1_TCLKDIV == CLK_DIV_4)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_4)
#elif (CONFIG_TIMER1_TCLKDIV == CLK_DIV_6)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_6)
#elif (CONFIG_TIMER1_TCLKDIV == CLK_DIV_8)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_8)
#elif (CONFIG_TIMER1_TCLKDIV == CLK_DIV_16)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_16)
#elif (CONFIG_TIMER1_TCLKDIV == CLK_DIV_32)
    #define TIMER1_TCLKDIV                       (TCLK_DIV_32)
#endif

#if (CONFIG_TIMER2_TCLKDIV == CLK_DIV_1)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_1)
#elif (CONFIG_TIMER2_TCLKDIV == CLK_DIV_2)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_2)
#elif (CONFIG_TIMER2_TCLKDIV == CLK_DIV_3)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_3)
#elif (CONFIG_TIMER2_TCLKDIV == CLK_DIV_4)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_4)
#elif (CONFIG_TIMER2_TCLKDIV == CLK_DIV_6)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_6)
#elif (CONFIG_TIMER2_TCLKDIV == CLK_DIV_8)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_8)
#elif (CONFIG_TIMER2_TCLKDIV == CLK_DIV_16)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_16)
#elif (CONFIG_TIMER2_TCLKDIV == CLK_DIV_32)
    #define TIMER2_TCLKDIV                       (TCLK_DIV_32)
#endif

#if (CONFIG_TIMER0_MODE == TIMER_13_MODE)
    #define TIMER0_MAX_VAL                       (8192)
#elif (CONFIG_TIMER0_MODE == TIMER_16_MODE)
    #define TIMER0_MAX_VAL                       (65536)
#elif ((CONFIG_TIMER0_MODE == TIMER_8_AUTO_MODE) || (CONFIG_TIMER0_MODE == TIMER_8_DIVID_MODE))
    #define TIMER0_MAX_VAL                       (256)
#else
    #error ("timer0 mode error")
#endif

#if (CONFIG_TIMER1_MODE == TIMER_13_MODE)
    #define TIMER1_MAX_VAL                       (8192)
#elif (CONFIG_TIMER1_MODE == TIMER_16_MODE)
    #define TIMER1_MAX_VAL                       (65536)
#elif (CONFIG_TIMER1_MODE == TIMER_8_AUTO_MODE)
    #define TIMER1_MAX_VAL                       (256)
#else
    #error ("timer1 mode error")
#endif

#define TIMER2_MAX_VAL                           (8192)

#if (CONFIG_TIMER0_FREQ < (SYS_SCLK_FREQ / CONFIG_TIMER0_TCLKDIV / (TIMER0_MAX_VAL-2)))
    #error("timer0 min frequery is out!!")
#elif (CONFIG_TIMER0_FREQ > (SYS_SCLK_FREQ / CONFIG_TIMER0_TCLKDIV / 2))
    #error("timer0 max frequery is out!!")
#endif

#if (CONFIG_TIMER1_FREQ < (SYS_SCLK_FREQ / CONFIG_TIMER1_TCLKDIV / (TIMER1_MAX_VAL-2)))
    #error("timer1 min frequery is out!!")
#elif (CONFIG_TIMER1_FREQ > (SYS_SCLK_FREQ / CONFIG_TIMER1_TCLKDIV / 2))
    #error("timer1 max frequery is out!!")
#endif

#if (CONFIG_TIMER2_FREQ < (SYS_SCLK_FREQ / CONFIG_TIMER2_TCLKDIV / (TIMER2_MAX_VAL-2)))
    #error("timer2 min frequery is out!!")
#elif (CONFIG_TIMER2_FREQ > (SYS_SCLK_FREQ / CONFIG_TIMER2_TCLKDIV / 2))
    #error("timer2 max frequery is out!!")
#endif

/**
 * @brief 
 * TCKL = SCLK / TCLK_DIV
 * freq = TCKL / (TIMER2_MAX_VAL - TIMER1_VAL)
 */
#define TIMER_RELOAD(MAX_VAL, TCLKDIV, FREQ) (MAX_VAL - (SYS_SCLK_FREQ / TCLKDIV / FREQ))

#define TIMER0_VAL                           TIMER_RELOAD(TIMER0_MAX_VAL, CONFIG_TIMER0_TCLKDIV, CONFIG_TIMER0_FREQ)
#define TIMER1_VAL                           TIMER_RELOAD(TIMER1_MAX_VAL, CONFIG_TIMER1_TCLKDIV, CONFIG_TIMER1_FREQ)
#define TIMER2_VAL                           TIMER_RELOAD(TIMER2_MAX_VAL, CONFIG_TIMER2_TCLKDIV, CONFIG_TIMER2_FREQ)

#define TIMER0_FREQ_VAL(FREQ)                     TIMER_RELOAD(TIMER0_MAX_VAL, CONFIG_TIMER0_TCLKDIV, FREQ)
#define TIMER1_FREQ_VAL(FREQ)                     TIMER_RELOAD(TIMER1_MAX_VAL, CONFIG_TIMER1_TCLKDIV, FREQ)
#define TIMER2_FREQ_VAL(FREQ)                     TIMER_RELOAD(TIMER2_MAX_VAL, CONFIG_TIMER2_TCLKDIV, FREQ)

/**
 * @brief timer reload via frequecy
 * The set frequency cannot exceed the count range of the timer
 * 
 */
#if ((CONFIG_TIMER0_MODE == TIMER_8_AUTO_MODE) || (CONFIG_TIMER0_MODE == TIMER_8_DIVID_MODE))
    #define TIMER0_FREQ_SET(FREQ)            WRITE_REG(TH0, TIMER0_FREQ_VAL(FREQ))
#else
    #define TIMER0_FREQ_SET(FREQ)            do{ WRITE_REG(TL0, (TIMER0_FREQ_VAL(FREQ) & 0xFF)); WRITE_REG(TH0, (TIMER0_FREQ_VAL(FREQ) >> 8) & 0xFF); } while (0)
#endif

#if ((CONFIG_TIMER1_MODE == TIMER_8_AUTO_MODE) || (CONFIG_TIMER1_MODE == TIMER_8_DIVID_MODE))
    #define TIMER1_FREQ_SET(FREQ)            WRITE_REG(TH1, TIMER1_FREQ_VAL(FREQ))
#else
    #define TIMER1_FREQ_SET(FREQ)            do{ WRITE_REG(TL1, (TIMER1_FREQ_VAL(FREQ) & 0xFF); WRITE_REG(TH1, (TIMER1_FREQ_VAL(FREQ) >> 8) & 0xFF); } while (0)
#endif

#define TIMER2_FREQ_SET(FREQ)                do{ WRITE_REG(TRL2, (TIMER2_FREQ_VAL(FREQ) & 0xff)); MODIFY_REG(TRH2_0, 0xE0, (((TIMER2_FREQ_VAL(FREQ) >> 8) & 0x7) << 5)); MODIFY_REG(TRH2_1, 0x60, (((TIMER2_FREQ_VAL(FREQ) >> 11) & 0x3) << 5));} while (0)


/* Please set these values according to SYS_SCLK_FREQ */
#if (CONFIG_IC_TYPE == CHIP_SS880X)
    #if (SYS_SCLK_FREQ == 12000000)
        #define TIMER_MODE      (TIMER_16_MODE)             /* 16-bit */
        #define TIMER_VAL       (65536)
        /* 1,2,3,4,6,8,16,32 */
        #define TIMER_TCLKDIV   (TCLK_DIV_2)
        /* 1000 / (SYS_SCLK_FREQ / TIMER_VAL / TIMER_TCLKDIV) */
        #define TICKS_10MS      (1)
        #define TICKS_100MS     (9)
        #define TICKS_500MS     (46)
        #define TICKS_1000MS    (92)

    #elif (SYS_SCLK_FREQ == 4000000)
        #define TIMER_MODE      (TIMER_13_MODE)             /* 13-bit */
        #define TIMER_VAL       (8192)
        /* 1,2,3,4,6,8,16,32 */
        #define TIMER_TCLKDIV   (TCLK_DIV_6)

        #define TICKS_10MS      (1)             //12.28ms
        #define TICKS_100MS     (8)             //98.24ms
        #define TICKS_500MS     (41)
        #define TICKS_1000MS    (82)            //1006.96ms

    #elif (SYS_SCLK_FREQ == 3000000)
        #define TIMER_MODE      (TIMER_13_MODE)             /* 13-bit */
        #define TIMER_VAL       (8192)
        /* 1,2,3,4,6,8,16,32 */
        #define TIMER_TCLKDIV   (TCLK_DIV_4)

        #define TICKS_10MS      (1)             //10.92ms
        #define TICKS_100MS     (9)
        #define TICKS_500MS     (46)
        #define TICKS_1000MS    (92)

    #elif (SYS_SCLK_FREQ == 187500)
        #define TIMER_MODE      (TIMER_8_AUTO_MODE)             /* 8-bit reload */
        #define TIMER_VAL       (234)
        /* 1,2,3,4,6,8,16,32 */
        #define TIMER_TCLKDIV   (TCLK_DIV_8)
        /* ms / (1000 / (SYS_SCLK_FREQ / TIMER_VAL / TIMER_TCLKDIV)) */
        #define TICKS_10MS      (1)
        #define TICKS_100MS     (10)
        #define TICKS_500MS     (50)
        #define TICKS_1000MS    (100)
    #else
        #error("Please define TICK VARIABLES according to SYS_SCLK_FREQ")
    #endif
#elif (CONFIG_IC_TYPE > CHIP_SS880X)
    #define TICKS_10MS         (1)
    #define TICKS_100MS        (9)
    #define TICKS_500MS        (46)
    #define TICKS_1000MS       (92)
#endif

#define STICK_ENABLE()                            SET_BIT(TICKCON, TICKEN_BIT)
#define STICK_DISABLE()                           CLEAR_BIT(TICKCON, TICKEN_BIT)
#define STICK_INTERRUPT_ENABLE()                  (ETICK = 1)
#define STICK_INTERRUPT_DISABLE()                 (ETICK = 0)

#define TIMER_0_ENABLE()                          (TR0 = 1)
#define TIMER_0_DISABLE()                         (TR0 = 0)
#define TIMER_0_INTERRUPT_ENABLE()                (ET0 = 1)
#define TIMER_0_INTERRUPT_DISABLE()               (ET0 = 0)

#define TIMER_1_ENABLE()                          (TR1 = 1)
#define TIMER_1_DISABLE()                         (TR1 = 0)
#define TIMER_1_INTERRUPT_ENABLE()                (ET1 = 1)
#define TIMER_1_INTERRUPT_DISABLE()               (ET1 = 0)

#define TIMER_2_ENABLE()                          (TR2 = 1)
#define TIMER_2_DISABLE()                         (TR2 = 0)
#define TIMER_2_INTERRUPT_ENABLE()                (ET2 = 1)
#define TIMER_2_INTERRUPT_DISABLE()               (ET2 = 0)

void timer_init(void);

#endif